#pragma once
#include <string>
#include <unistd.h>
#include <pthread.h>
#include <vector>
#include <string>
#include <queue>
#include "Task.hpp"

struct ThreadPoolInfo
{
    ThreadPoolInfo() = default;
    ThreadPoolInfo(pthread_t id, std::string name)
        : id_(id), name_(name)
    {
    }
    pthread_t id_;
    std::string name_;
};

template <typename T>
class ThreadPool
{
    const static int default_num = 5;

private:
    void Lock()
    {
        pthread_mutex_lock(&lock_);
    }
    void UnLock()
    {
        pthread_mutex_unlock(&lock_);
    }
    void Wait()
    {
        pthread_cond_wait(&cond_, &lock_);
    }
    void WakeUp()
    {
        pthread_cond_signal(&cond_);
    }
    bool IsQueueEmpry()
    {
        return tasks_.empty();
    }
    std::string GetName()
    {
        for (auto &e : threads_)
        {
            if (pthread_self() == e.id_)
            {
                return e.name_;
            }
        }
        return "";
    }

    ThreadPool(int num = default_num)
        : num_(num), threads_(num)
    {
        pthread_mutex_init(&lock_, nullptr);
        pthread_cond_init(&cond_, nullptr);
    }

    ~ThreadPool()
    {

        for (auto &e : threads_)
        {
            pthread_join(e.id_, nullptr);
        }
        pthread_mutex_destroy(&lock_);
        pthread_cond_destroy(&cond_);
    }
public:
    ThreadPool(const ThreadPool<T>& tp)=delete;
    ThreadPool<T>& operator=(ThreadPool<T> tp)=delete;
    static ThreadPool<T> *GetThreadPool()
    {
        if (singleton_ == nullptr)
        {
            pthread_mutex_lock(&class_mutex_);
            if (singleton_ == nullptr)
            {
                singleton_ = new ThreadPool<T>();
            }
            pthread_mutex_unlock(&class_mutex_);
        }

        return singleton_;
    }
    
    static void DelThreadPool()
    {
        pthread_mutex_lock(&class_mutex_);
        if(singleton_)
        {
            delete singleton_;
            singleton_ = nullptr;
        }
        pthread_mutex_unlock(&class_mutex_);
    }
    void Run()
    {
        int num = threads_.size();
        for (int i = 0; i < num; ++i)
        {
            threads_[i].name_ = "thread-" + std::to_string(i + 1);
            pthread_create(&threads_[i].id_, nullptr, HandlerTask, this);
        }
    }

    static void *HandlerTask(void *args)
    {
        ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(args);
        while (true)
        {
            tp->Lock();
            while (tp->IsQueueEmpry())
            {
                tp->Wait();
            }
            T t = tp->Pop();
            tp->UnLock();
            // 处理数据
            t();
            // std::string name = tp->GetName();
            // std::cout << name << " run, result: " << t.get_result() << std::endl;
        }
    }

    T Pop()
    {
        T t = tasks_.front();
        tasks_.pop();
        return t;
    }

    void Push(const T &t)
    {
        Lock();
        tasks_.push(t);
        WakeUp();
        UnLock();
    }

    

private:
    std::queue<T> tasks_;
    std::vector<ThreadPoolInfo> threads_; // 线程信息
    int num_;                             // 线程数量
    pthread_mutex_t lock_;
    pthread_cond_t cond_;

    static ThreadPool<T> *singleton_;
    static pthread_mutex_t class_mutex_;
};

template <typename T>
ThreadPool<T> *ThreadPool<T>::singleton_ = nullptr;

template <typename T>
pthread_mutex_t ThreadPool<T>::class_mutex_ = PTHREAD_MUTEX_INITIALIZER;